package cn.z2huo.knowledge.concurrency.producerconsumer;

import java.util.LinkedList;
import java.util.List;

/**
 * <p>
 *
 * @author z2huo
 */
class DataBuffer<T> {

    /**
     * 队列中同时存在元素的最大数量
     */
    private static final int MAX_AMOUNT = 10;

    private final List<T> dataList = new LinkedList<>();

    /**
     * 当前队列中存在元素数量
     */
//    private final AtomicInteger amount = new AtomicInteger(0);
    private int amount = 0;

    /**
     * 用于临界区资源同步
     */
    private final Object lock = new Object();

    /**
     * 用于数据缓冲区未满条件的等待通知
     */
    private final Object notFullLock = new Object();

    /**
     * 用于数据缓冲区不为空的条件等待通知
     */
    private final Object notEmptyLock = new Object();

    /**
     * 向数据区域添加元素
     * @param element   待添加元素
     */
    public void add(T element) {

        while (amount >= MAX_AMOUNT) {
            synchronized (notFullLock) {
                System.out.println("队列已满");
                try {
                    notFullLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        synchronized (lock) {
            dataList.add(element);
            System.out.println("add element, element is " + element);
            amount++;
        }

        synchronized (notEmptyLock) {
            // 发送非空通知
            notEmptyLock.notify();
        }

//        if (amount != dataList.size()) {
//            throw new RuntimeException("数据不一致, " + amount + " != " + dataList.size());
//        }
    }

    /**
     * 从数据区域中取出一个元素
     */
    public T fetch() {
        while (amount <= 0) {
            synchronized (notEmptyLock) {
                System.out.println("队列已空");
                try {
                    notEmptyLock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        T element;
        synchronized (lock) {
            element = dataList.removeFirst();
            System.out.println("fetch element, element is " + element);
            amount--;
        }

        synchronized (notFullLock) {
            // 发送未满通知
            notFullLock.notify();
        }

//        if (amount != dataList.size()) {
//            throw new RuntimeException("数据不一致, " + amount + " != " + dataList.size());
//        }
        return element;
    }

}
